#ifndef P_EVENT_DISPATCHER_H
#define P_EVENT_DISPATCHER_H

#include "PEvent.h"
#include "PKeyInputEvent.h"
#include "PMouseInputEvent.h"
#include "PWindowEvent.h"

namespace Piccolo
{
    class PEventObserver;

    using Func_EventHandle = std::function<void(PEvent& e)>;

    struct EventHandler
    {
        PEventObserver* observer;
        Func_EventHandle func;
    };

    class PEventDispatcher
    {
    public:
        PEventDispatcher(const PEventDispatcher&) = delete;
        PEventDispatcher& operator=(const PEventDispatcher&) = delete;
        ~PEventDispatcher();

        static PEventDispatcher* GetInstance() { return &s_Instance; }

        template<typename T>
        void AddObserverHandler(PEventObserver* observer, const std::function<void(const T&)>& func)
        {
            if (!observer || !func) return;

            auto eventFunc = [func](const PEvent& e)
            {
                const T& event = static_cast<const T&>(e);
                return func(event);
            };

            EventHandler handler
            {
                .observer = observer,
                .func = eventFunc
            };
            mObserverHandlerMap[T::GetStaticType()].emplace_back(handler);
        }

        void DestroyObserver(PEventObserver* observer)
        {
            for (auto& item : mObserverHandlerMap)
            {
                item.second.erase(std::remove_if(item.second.begin(), item.second.end(), [observer](const EventHandler& handler)
                {
                    return handler.observer && handler.observer == observer;
                }), item.second.end());
            }
        }

        void Dispatch(PEvent& event);

    private:
        PEventDispatcher() = default;

        static PEventDispatcher s_Instance;

        std::unordered_map<EEventType, std::vector<EventHandler>> mObserverHandlerMap;
    };
}

#endif